#include <queue>
#include <string>
using namespace std;

class Weapon
{
	public:
		unsigned char maxBullets;
		string name;
		unsigned char bulletsRemaining;
		unsigned char ammoRemaining;
		float damageFactor;

		Weapon()
		{
			maxBullets = 7;
			name = "Hand Gun";
			bulletsRemaining = 7;
			ammoRemaining = 0;
			damageFactor = 0;
		}

		Weapon(string n, unsigned char maxB)
		{
			name = n;
			maxBullets = maxB;
			bulletsRemaining = maxB;
			ammoRemaining = 0;
			damageFactor = 0;
		}

		float shoot(void)
		{
			if (bulletsRemaining != 0)
			{
				--bulletsRemaining;
				return damageFactor;
			}
			return -1.0;
		}

		void reload(void)
		{
			if (ammoRemaining >= maxBullets)
			{
				bulletsRemaining = maxBullets;
				ammoRemaining -= maxBullets;
			}
		}
};

class Player
{
	public:
		string name;
		char health;
		char armor;
		Weapon currentWeapon;
		queue<Weapon> weapons;
		int highScore;
		int currentScore;

		Player(string n)
		{
			name = n;
			health = 100;
			armor = 0;
			weapons.push(*(new Weapon()));
			currentWeapon = weapons.front();
			highScore = 0;
			currentScore = 0;
		}

		Player(string n, int highS)
		{
			name = n;
			health = 100;
			armor = 0;
			weapons.push(*(new Weapon()));
			currentWeapon = weapons.front();
			currentScore = 0;
			highScore = highS;
		}

		float shoot(void)
		{
			return currentWeapon.shoot();
		}

		void reload(void)
		{
			currentWeapon.reload();
		}

		bool giveWeapon(Weapon w)
		{
			Weapon* ptr;
			Weapon currElem;
			ptr = &weapons.front();
			for (unsigned char i = 0; i < weapons.size(); ++i)
			{
				currElem = *ptr;
				if (currElem.name == w.name)
					return false;
				ptr++;
			}
			weapons.push(w);
			return true;
		}

		void updateHighScore(void)
		{
			highScore = (currentScore > highScore) ? currentScore : highScore;
		}

		void plusScore(int x)
		{
			currentScore += x;
		}

		void giveHealth(char h)
		{
			health = ((health + h) >= 100) ? 100 : health + h;
		}

		void giveArmor(char a)
		{
			armor = ((armor + a) >= 100) ? 100 : armor + a;
		}

};

class Target
{
	public:
		int bounty;
		int distFromObserver;
		int health;
		bool isDestroyed;
		//OpenGL vectors and position tracking of a traget can be declared here.
		Target(int d)
		{
			distFromObserver = d;
			bounty = 5 * distFromObserver;
			health = 0;
		}

		Target(int d, int h)
		{
			distFromObserver = d;
			health = h;
			bounty = h * distFromObserver * 5;
		}

		int destroyTarget(void)
		{
			if (isDestroyed)
				return -1;
			isDestroyed = true;
			return bounty;
		}

		int giveDamage(int dmgAmt)
		{
			if (dmgAmt >= health)
				return destroyTarget();
			else
			{
				health -= dmgAmt;
				return 0;
			}
		}
};

class Engine
{
	public:
		static Player currentPlayer;
		static queue<Target> targets;
		static unsigned char difficulty;
		static void initPlayer(string n)
		{
			currentPlayer = *(new Player(n));
		}

		static void setDifficulty(unsigned char d)
		{
			difficulty = d;
		}

		static void initTargets(void)
		{
			//Loops on the targets Queue and sets their health to difficulty.
			//However, I need the fixed (FOR NOW) distances from the observer to init a target.
		}

		static void shootTarget(Target t)
		{
			float dmgFac = currentPlayer.shoot();
			if (dmgFac != -1.0)
			{
				t.giveDamage(dmgFac);
				currentPlayer.plusScore(t.bounty);
			}
		}

		static void reload()
		{
			currentPlayer.reload();
		}

		static void updateHighScore(void)
		{
			currentPlayer.updateHighScore();
		}

		static void pickHealth(char x)
		{
			currentPlayer.giveHealth(x);
		}

		static void pickArmor(char x)
		{
			currentPlayer.giveArmor(x);
		}

		static bool pickWeapon(Weapon w)
		{
			return currentPlayer.giveWeapon(w);
		}
};
